#ifndef AIR_HPP
#define AIR_HPP
//=========================================================
#include "airline.hpp"
#include <string.h>
#include <stdlib.h>
#include "minefield.hpp"
#include <time.h>
//=========================================================
//  LINKED STATES
//=========================================================
//  1 - SID
//  2 - STAR
//=========================================================
struct linked_states{
  int id;
  int airline_1;
  int airline_2;
  int quant_state_1;
  int quant_state_2;
  char *name_1;
  char *name_2;
  double x1;
  double x2;
  double y1;
  double y2;
  linked_states *next;
};
//=========================================================
//  CLASS AIR
//=========================================================
//  ВТ - воздушная трасса
//  КС - квантовое состояние
//=========================================================
class air{
  //const char *name; //название топологии
  char *name; //название топологии
  airline **airlines;
  int airlines_count; //количество ВТ
  int max_state_count; //max количество КС: приведение всех к max
  minefield ****mine_field; //текущий оператор R
  minefield ****old_mf; //исходный оператор R
  int old_state_count; //количество КС до усечения R
  linked_states *lstates; //список всех связных состояний
  double min_r; //min радиус сближения
  int min_flight; //min высота при взлете
  double **distr; //распределение STAR
  int star_count; //количество STAR
  int sid_count; //количество SID
  double *airline_distr; // распределение по ВТ
  double tau; //кол-во секунд, время одной операции взлет/посадка, время занятости ВПП
public:
  air(){
    //TODO
    //чтение из сохраненного файла
    //заполнение всех полей всех объектов
    //восстановление прежнего состояния
    name = NULL;
    airlines = NULL;
    airlines_count = 0;
    max_state_count = 0;
    old_state_count = 0;
    lstates = NULL;
    mine_field = NULL;
    old_mf = NULL;
    min_flight = 6;
    sid_count = 0;
    star_count = 0;
    distr = NULL;
    airline_distr = NULL;
    tau = 60;
  }
  //-------------------------------------------------------
  air(char *filename){
    FILE *fd;
    char path[100];
    snprintf(path,sizeof(path),"maps/%s",filename);
    fd = fopen(path,"r");
    if(fd == NULL){
      perror("Error: opening file source");
    }else{
      name = NULL;
      airlines = NULL;
      airlines_count = 0;
      max_state_count = 0;
      old_state_count = 0;
      lstates = NULL;
      mine_field = NULL;
      old_mf = NULL;
      this->name = filename;
      min_flight = 6;
      sid_count = 0;
      star_count = 0;
      distr = NULL;
      airline_distr = NULL;
      tau = 60;
      this->get_topology(fd);
      fclose(fd);
    }
  }
  //-------------------------------------------------------
  ~air(){ //деструктор
    //TODO
    //сохранение всех данных в файл, из которого
    //в конструкторе восстанавливается прежнее состояние
  }
  //-------------------------------------------------------
  //получить название топологии
  char *get_name(){ return this->name; }
  //-------------------------------------------------------
  // Задать tau
  void set_tau(double value){ this->tau = value; }
  // Получить tau
  double get_tau(){ return this->tau; }
  //загрузка топологии ВТ из файла
  void get_topology(FILE *fs){
    char *name,type[4],gps[1000];
    double height; //высота ВПП
    int als_dim; //количество ВТ
    fscanf(fs,"%le\n",&height);
    fscanf(fs,"%i\n",&als_dim);
    this->airlines_count = als_dim;
    this->airlines = new airline*[als_dim];
    for(int i=0; i<als_dim; i++){ //для каждой ВТ
      name = new char[20];
      fscanf(fs,"%s\n",name); //название ВТ
      fscanf(fs,"%s\n",type); //тип ВТ
      fscanf(fs,"%s",gps); //строка координат ВТ
      //увеличиваем счетчик соответствующего типа ВТ в топологии
      if(strcmp(type,"SID") == 0)
        this->sid_count++;
      else
        this->star_count++;
      //разбор строки координат ВТ (side:c1,c2/side:c3,c4#speed;)
      int count = 0; //сколько всего точек для данной ВТ
      for(size_t j=0; j<strlen(gps); j++){
        if(gps[j] == ';')
          count++;
      }
      count *= 3; //2 координаты и скорость на каждую точку
      //printf("count = %d\n", count);
      vector gps_c(count);
      char *gps_tmp;
      int side_flag = 0; //флаг на смену знака для стороны света
      int indx = 0;
      gps_tmp = strtok(gps,":,/;#");
      int count_flag = 1; //флаг для перевода координат
      double tmp;
      while(gps_tmp != NULL){
        if((count_flag != 1) && (count_flag != 4)){
          if((count_flag <= 6)){
            //запоминаем градусы
            gps_c[indx] = atof(gps_tmp);
            //делаем перевод минут.сек в градусы + минут.сек/60
            if((count_flag%3) == 0){
              tmp = gps_c[indx-1] + atof(gps_tmp)/60;
              gps_c[indx-1] = tmp;
              //если S или W меняем знак
              if(side_flag > 0){
                gps_c[indx-1] *= -1;
                side_flag = 0;
              }
            }else{
              indx++;
            }
          }else{
            //записываем скорость
            gps_c[indx] = atof(gps_tmp);
            indx++;
            count_flag = 0;
          }
        }
        if((strcmp(gps_tmp,"N") == 0) || (strcmp(gps_tmp,"E") == 0)){
          side_flag = 0; //если N или E не меняем знак
        }
        if((strcmp(gps_tmp,"W") == 0) || (strcmp(gps_tmp,"S") == 0)){
          side_flag = 2; //если W или S меняем знак
        }
        count_flag++;
        gps_tmp = strtok(NULL,":,/;#");
      }
      //добавление очередной ВТ
      this->airlines[i] = new airline;
      this->airlines[i]->set_name(name);
      this->airlines[i]->set_sidstar(type);
      height *= 0.3048;
      for(int k=0; k<count/3; k++){
        //add(lat,lon,height,speed,spher,ellipse)
        // printf("k = %d %g\t%g \t%g\n",k,gps_c[3*k],gps_c[3*k+1],gps_c[3*k+2]);
        this->airlines[i]->add(gps_c[3*k],gps_c[3*k+1],height,gps_c[3*k+2],false,true);
        
      }
    }
    delete name;
  }
  //-------------------------------------------------------
  //печать данных о ВТ в топологии
  void print(FILE *fd){
    fprintf(fd,"Air_name: %s\n",this->get_name());
    for(int i=0; i<this->airlines_count; i++){
      this->airlines[i]->print(fd);
    }
  }
  //-------------------------------------------------------
  //интерполяция ВТ
  void interpolation(){
    char path[100], logpath[100], *name;
    char *topology_name;
    FILE *fp, *flog;
    printf("interpolation of airlines\n");
    topology_name = this->get_name();
    snprintf(logpath,sizeof(logpath),"logs/interpolation_%s",topology_name);
    flog = fopen(logpath,"w+");
    fprintf(flog,"CUBE_SPLINES for TOPOLOGY: %s\n",topology_name);
    for(int i=0; i<this->airlines_count; i++){
      fprintf(flog,"\n==============================\n\n");
      name = this->airlines[i]->get_name();
      fprintf(flog,"%s\n",name);
      snprintf(path,sizeof(path),"splines/%s/%s",topology_name,name);
      fp = fopen(path,"w+");
      this->airlines[i]->calc_len();
      printf("before: %s %g\n", this->airlines[i]->get_name(),this->airlines[i]->get_len());
      this->airlines[i]->spline(fp,flog);
      this->airlines[i]->calc_len();
      printf("after: %s %g\n", this->airlines[i]->get_name(),this->airlines[i]->get_len());
      fclose(fp);
    }
    fclose(flog);
  }
  //-------------------------------------------------------
  //получение распределения потока STAR для заданной топологии ВТ
  void get_distr(const char *filename){
    FILE *fd = fopen(filename,"r");
    if(fd == NULL){
      perror("Error: opening distr file source\n");
    }else{
      double **distr;
      distr = new double*[this->star_count];
      for(int i = 0; i < this->star_count; ++i){
        distr[i] = new double[this->max_state_count];
        for (int j = 0; j < this->max_state_count; ++j){
          fscanf(fd,"%le",&distr[i][j]);
        }
      }
      this->distr = distr;
      fclose(fd);
    }
  }
  //получение распределения по ВТ 
  void get_airline_distr(const char *filename){
    FILE *fd = fopen(filename,"r");
    if(fd == NULL){
      perror("Error: opening airline distr file source\n");
    }else{
      this->airline_distr = new double[this->airlines_count];
      for(int i = 0; i<this->airlines_count; ++i){
        fscanf(fd,"%le",&this->airline_distr[i]);
      }
      fclose(fd);
    }
  }
  //выбор новой ВТ c учетом распределения по ВТ
  int get_new_airline(const char *type){
    if(this->airline_distr != NULL){
      //перевод распределения для более удобного расчета
      double sum = 0;
      if(strcmp(type,"SID") == 0){
        double air_distr_sid[this->sid_count];
        int sid_num = 0;
        for (int i = 0; i < this->airlines_count; ++i){
            if(strcmp(this->airlines[i]->get_sidstar(),"SID") != 0) continue;
            if(this->airline_distr[i] != 0){
              sum = sum + this->airline_distr[i];
              air_distr_sid[sid_num] = sum;
            }else{
              air_distr_sid[sid_num] = -1;
            }
            // printf("[%d]sid[%d]= %g\n",i,sid_num,air_distr_sid[sid_num]);
            sid_num++;
        }
        int new_line = rand() % (int)(floor(sum+1)); // число от 0 до sum
        double prev = 0;
        for(int i = 0; i<this->sid_count; ++i){
          if(air_distr_sid[i] == -1) continue;
          if((double)new_line >= prev && (double)new_line <= air_distr_sid[i]){
            // printf("sum = %d, new_line = %g, #%d\n",(int)(floor(sum+1)),(double)new_line, i );
            return i;
          }
          prev = air_distr_sid[i];
        }
      }else{ // Для STAR
        double air_distr_star[this->star_count];
        int star_num = 0;
        for (int i = 0; i < this->airlines_count; ++i){
            if(strcmp(this->airlines[i]->get_sidstar(),"STAR") != 0) continue;
            if(this->airline_distr[i] != 0){
              sum = sum + this->airline_distr[i];
              air_distr_star[star_num] = sum;
            }else{
              air_distr_star[star_num] = -1;
            }
            // printf("[%d]star[%d]= %g\n",i,star_num,air_distr_star[star_num]);
            star_num++;
        }
        int new_line = rand() % (int)(floor(sum+1)); // число от 0 до sum
        double prev = 0;
        for(int i = 0; i<this->star_count; ++i){
          if(air_distr_star[i] == -1) continue;
          if((double)new_line >= prev && (double)new_line <= air_distr_star[i]){
            // printf("sum = %d, new_line = %g, #%d\n",(int)(floor(sum+1)),(double)new_line, i );
            return i;
          }
          prev = air_distr_star[i];
        }
      } 
    }
    return -1;// вернем ошибку
  }
  //-------------------------------------------------------
  //вычисление квантовых состояний
  void count_quant_states(){
    for(int i=0; i<this->airlines_count; i++){
      this->airlines[i]->calc_len();
      this->airlines[i]->calc_quant_state_len(this->get_tau());
      this->airlines[i]->get_speed_len(this->get_tau());

      this->airlines[i]->get_speed_quant_state_count();

      // this->airlines[i]->calc_quant_state_count();
      // this->airlines[i]->set_quant_state_point();

      printf("%g\n",this->airlines[i]->get_quant_state_len());
      printf("%d\n",this->airlines[i]->get_quant_state_count());
    }
    this->max_quant_state_count();
  }
  //-------------------------------------------------------
  //напечатать распределение
  void print_distr(){
    if(this->distr != NULL){
      for (int i=0; i<this->star_count; ++i){
        for (int j=0; j<this->max_state_count; ++j){
          printf("%g ",this->distr[i][j]);
        }
        printf("\n");
      }
    }
  }
  //-------------------------------------------------------
  //поиск max кол-ва квантовых состояний
  void max_quant_state_count(){
    int max_count = 0;
    for(int i=0; i<this->airlines_count; i++){
      if(this->airlines[i]->get_quant_state_count() > max_count)
        max_count = this->airlines[i]->get_quant_state_count();
    }
    this->max_state_count = max_count;
  }
  //-------------------------------------------------------
  //получить max кол-во квантовых состояний в топологии
  int get_max_quant_state(){ return this->max_state_count; }
  //-------------------------------------------------------
  //
  void set_min_r(double val){ this->min_r = val; }
  //-------------------------------------------------------
  //поиск пересекающихся ВТ
  void set_linked_qstate(FILE *fd){
  	qstate *qst1, *qst2, *first1, *first2;
    int id = 10;
    linked_states *tmp; 
    //qst1 - SID
    //qst2 - STAR
    for(int i=0; i<this->airlines_count; i++){
      if(strcmp(this->airlines[i]->get_sidstar(),"SID") != 0) continue;
      first1 = this->airlines[i]->get_quant_states();
      for(int j=0; j<this->airlines_count; j++){
        if(strcmp(this->airlines[j]->get_sidstar(),"STAR") != 0) continue;
        qst1 = first1;
      	first2 = this->airlines[j]->get_quant_states();
      	//сравниваем точки КС если меньше чем заданный минимум(min_r) то заносим в в списко пересечений
      	while(qst1 != NULL){
      		qst2 = first2;
      	  while(qst2 !=NULL){
    		    if(sqrt(pow(qst2->cx - qst1->cx,2)+pow(qst2->cy - qst1->cy,2)) < this->min_r){
    		   	  tmp = new linked_states;
              tmp->id = id;
    		   	  tmp->airline_1 = i;
    		   	  tmp->airline_2 = j;
    		   	  tmp->quant_state_1 = qst1->num;
    		   	  tmp->quant_state_2 = qst2->num;
    		   	  tmp->x1 = qst1->cx;
    		   	  tmp->x2 = qst2->cx;
    		   	  tmp->y1 = qst1->cy;
    		   	  tmp->y2 = qst2->cy;
    		   	  tmp->name_1 = this->airlines[i]->get_name();
    		   	  tmp->name_2 = this->airlines[j]->get_name();	
    		   	  tmp->next = this->lstates;	   	 
    		   	  this->lstates = tmp;
              ++id;
    		    }
    		    qst2 = qst2->next;      		
        	}
        	qst1 = qst1->next;
      	}
      }
    }
    //-------------------------------------------------------
    // вывод данных, как в файл, так и на экран
    FILE *fr;
    char path[100];
    snprintf(path,sizeof(path),"splines/%s/%s",this->name,"link_qst");
    fr = fopen(path,"w");
    tmp = lstates;
    while(tmp != NULL){
    	fprintf(fr,"%g \t  %g\n%g \t  %g\n",tmp->x1,tmp->y1,tmp->x2,tmp->y2);
      fprintf(fd,"id=%d | %s: # = %d, qst = %d  <----> %s # = %d, qst = %d\n",tmp->id,tmp->name_1,tmp->airline_1,tmp->quant_state_1,tmp->name_2,tmp->airline_2,tmp->quant_state_2);
    	tmp = tmp->next;
    }
    fclose(fr);
  }
  linked_states *get_lstates(){ return this->lstates; }
  void print_gnuplot(){
    FILE *fd;
    char path[100];
    snprintf(path,sizeof(path),"splines/%s/plot_%s.gnu",this->name,this->name);
    fd = fopen(path,"w+");
    if(fd == NULL){
      perror("Error: opening file for gnuplot\n");
    }else{
      fprintf(fd, "set nokey\n");
      fprintf(fd, "set terminal pdf\n");
      fprintf(fd, "set output '%s.pdf'\n\n",this->name);
      fprintf(fd, "plot ");
      for(int i=0; i<this->airlines_count; i++){
        fprintf(fd, "'./%s' with line, ",this->airlines[i]->get_name());
      }
      fprintf(fd, "'./link_qst' with point\n\n");
      fprintf(fd, "#pause -1\n");
      fclose(fd);
    }
  }
  //-------------------------------------------------------
  //плотность связных состояний в системе
  void ks_in_matrix(){
    double ks = pow(this->max_state_count,2) * this->airlines_count;
    printf("max state count = %d, airlines = %d\n",this->max_state_count,this->airlines_count );
    double ks_sv = 0;
    for(int i=0; i<this->airlines_count; i++){
      for (int j=0; j<this->max_state_count; j++){
        for (int k=0; k<this->max_state_count; k++){
          if(this->mine_field[i][j][k]->get_id() == 5)
            ks_sv++;
        }
      }
    }
    printf("всего: %g связных: %g\n", ks, ks_sv);
    double plotn = ks_sv/ks;
    printf("плотность связных квантовых состояний = %g\n",plotn);
  }
  //=======================================================

  //=======================================================
  //  МИННОЕ ПОЛЕ ДЛЯ ЗАДАННОЙ ТОПОЛОГИИ
  //=======================================================
  //получить текущий оператор R
  minefield ****get_mine_field(){ return this->mine_field; }
  //-------------------------------------------------------
  //получить исходный оператор R
  minefield ****get_old_mf(){ return this->old_mf; }
  //-------------------------------------------------------
  //построение
  void generate_mine_field(/*struct l_airlines;*/){
    linked_states *lst = this->lstates;
    int st_count = this->max_state_count;
    // 0 - состояние свободно
    // 1 - состояние невозможно занять (проблема быстрого взелта/посадки)
    // 5 - Связные КС
    minefield ****MINE;
    MINE = new minefield***[this->airlines_count];
    for (int i = 0; i < this->airlines_count; ++i){
      MINE[i] = new minefield**[st_count];
    }
    //создание структуры минного поля и заполнение значениями по уломчанию
    if((st_count - min_flight) < 3) min_flight = 0;
    int r = 2*(st_count-1) - min_flight;
    for (int i=0; i<this->airlines_count; ++i){
      for (int j=0; j<st_count; ++j) {
        MINE[i][j] = new minefield*[st_count];
        for (int k = 0; k < st_count; ++k){
          MINE[i][j][k] = new minefield;
          if( k < st_count-j -1){
            MINE[i][j][k]->set_id(1);
          }
          if(k+j > r && strcmp(this->airlines[i]->get_sidstar(),"SID") == 0){
            MINE[i][j][k]->set_id(1);
          }
        }
      }
    }
    while(lst != NULL){
      // Выставляем по высотам
      for (int i = 0; i < st_count; ++i){
        if(MINE[lst->airline_1][i][lst->quant_state_1]->get_id() != 1  && MINE[lst->airline_2][i][lst->quant_state_2]->get_id() != 1){
          MINE[lst->airline_1][i][lst->quant_state_1]->add(lst->id,lst->airline_2,lst->quant_state_2);
          MINE[lst->airline_1][i][lst->quant_state_1]->set_id(5);
          MINE[lst->airline_2][i][lst->quant_state_2]->add(lst->id,lst->airline_1,lst->quant_state_1);
          MINE[lst->airline_2][i][lst->quant_state_2]->set_id(5);  
        }
      }
      lst = lst->next;
    }
    this->mine_field = MINE;
  }
  //-------------------------------------------------------
  //проверка свободно ли связное КС  
  bool is_busy(int i, int new_j, int k){
    minefield ****MINE;
    MINE = this->mine_field;
    if(MINE[i][new_j][k]->get_id() != 5) return false; //если не связное КС
    numbers *tmp;
    tmp = MINE[i][new_j][k]->get_links();
    while(tmp != NULL){
      if(MINE[tmp->airline_id][new_j][tmp->qst]->is_plane()){
        return true;
      }
      tmp = tmp->next;
    }
    return false;
  }
  //выбор нового КС (новой высоты)
  int get_new_j(int i,int j,int k,bool clever = false){
    minefield ****MINE;
    MINE = this->mine_field;
    int new_j;
    //-----------------------------------------------------
    //для SID:
    if(strcmp(this->airlines[i]->get_sidstar(),"SID") == 0){
      if(MINE[i][j][k+1]->get_id() != 1){
        if(j != 0 && MINE[i][j-1][k+1]->get_id() != 1){
          int rj = rand() % 2;  
          new_j = j-rj;
        }else{
          new_j = j;
        }
      }else{
        new_j = j-1;
      }
      //производим проверку и возможно выбрать другой вариант высоты
      if(this->is_busy(i,new_j,k+1) && clever){ //если конфликт в текущем выбранном
        if(new_j == j && j != 0 && MINE[i][j-1][k+1]->get_id() != 1){ 
          new_j = j-1; // выбираем спускатся вниз, т.к. в любом случае больше не куда, и в случае елси
                      // оба состояния связные и в обоих конфликты, это КС - поумолчанию
          // printf("Меняем эшелон для SID на j-1\n");
        }else if(new_j == j-1 && MINE[i][j][k+1]->get_id() != 1){
          if(!this->is_busy(i,j,k+1)){ // если свободно состояние эшелоном выше от выбранного (j === new_j+1)
            new_j = j;                // раз свободно, выбираем его
            // printf("Меняем эшелон для SID на j\n");
          }
        }
      }
    //-----------------------------------------------------
    //для STAR:
    }else{
      int st_count = this->max_state_count;
      if(MINE[i][j][k-1]->get_id() != 1){
        if(j != st_count-1 && MINE[i][j+1][k-1]->get_id() != 1){
          int rj = rand() % 2;
          new_j = j+rj;
        }else{
          new_j = j;
        }
      }else{
        new_j = j+1;
      }
      // производим проверку и возможно выбрать другой вариант высоты
      if(this->is_busy(i,new_j,k-1) && clever){ // если конфликт в текущем выбранном
        if(new_j == j && j != st_count-1 && MINE[i][j+1][k-1]->get_id() != 1){ 
          new_j = j+1; // выбираем подниматься вверх, т.к. нынешнее точно конфликтное, а по умолчанию взлетать
          // printf("Меняем эшелон для STAR на j+1\n");
        }else if(new_j == j+1 && MINE[i][j][k-1]->get_id() != 1){
          if(!this->is_busy(i,j,k-1)){ // если свободно состояние эшелоном ниже т.е. исходное (j === new_j)
            new_j = j;
            // printf("Меняем эшелон для STAR на j\n");
          }
        }
      }
    }
    return new_j;
  }
  //-------------------------------------------------------
  // печать минного поля
  void print_mine_field(FILE *fd,minefield ****mine,int dim){
    for(int i=0; i<this->airlines_count; ++i){
      fprintf(fd,"%s : %s -> 0 - Свободно, 1 - запрещено, 5 - Связные КС\n", this->airlines[i]->get_name(), this->airlines[i]->get_sidstar());
      bool pr = true;
      for(int j=0; j<dim; ++j){
        for (int k=0; k<dim; ++k){
          if(pr){
            if(k<10) fprintf(fd,"%d  ",k);
            else fprintf(fd,"%d ", k);
          }else{
            fprintf(fd,"%d  ", mine[i][j][k]->get_id());  
          }
        }
        if(pr){
          fprintf(fd,"\n");
          pr = false;
          --j;
        }
        fprintf(fd,"\n");
      }
      fprintf(fd,"\n");
    }
    fprintf(fd,"\n");
  }
  //-------------------------------------------------------
  //запись матриц в файл для визуализации
  void make_a_view(){
    FILE *fv,*fvt;
    char path[100];
    char *topology_name;
    topology_name = this->get_name();
    snprintf(path,sizeof(path),"view/%s",topology_name);
    fv = fopen(path,"w");
    snprintf(path,sizeof(path),"view/trunc_%s",topology_name);
    fvt = fopen(path,"w");
    if((fv == NULL)||(fvt == NULL)){
      perror("Error: opening file source");
    }else{
      fprintf(fv,"%d\n",this->airlines_count);
      fprintf(fvt,"%d\n",this->airlines_count);
      for(int i=0; i<this->airlines_count; i++){
        fprintf(fv,"%s %d %d\n", this->airlines[i]->get_name(), this->old_state_count, this->old_state_count);
        fprintf(fvt,"%s %d %d\n", this->airlines[i]->get_name(), this->max_state_count, this->max_state_count);
        for (int j=0; j<this->old_state_count; ++j){
          for (int k=0; k<this->old_state_count; ++k){
            fprintf(fv,"%d", this->old_mf[i][j][k]->get_id());  
          }
          fprintf(fv,"\n");
        }
        for (int j=0; j<this->max_state_count; ++j){
          for (int k=0; k<this->max_state_count; ++k){
            fprintf(fvt,"%d", this->mine_field[i][j][k]->get_id());  
          }
          fprintf(fvt,"\n");
        }
      }
      fclose(fv);
      fclose(fvt);
    }
  }
  //-------------------------------------------------------
  //поиск max допустимых FL по столбцам, в которых есть связные КС
  int get_height(minefield ****MINE,int airline,int quant_state){
    int height = 0;
    for(int i=0; i<this->max_state_count; i++){
      if(MINE[airline][i][quant_state]->get_id() != 1){
        height = this->max_state_count - i;
        break;
      }
    }
    return height;
  }
  void get_max_heights(){
    minefield ****MINE;
    MINE = this->mine_field;
    FILE *fr;
    char path[100];
    char *topology_name;
    topology_name = this->get_name();
    snprintf(path,sizeof(path),"logs/max_heights_%s",topology_name);
    fr = fopen(path,"w+");
    //int qs = 0;
    linked_states *LIST;
    LIST = this->get_lstates();
    int mh_1 = 0;
    int mh_2 = 0;
    while(LIST != NULL){
      fprintf(fr,"%s-%s ", LIST->name_1, LIST->name_2);
      mh_1 = get_height(MINE,LIST->airline_1,LIST->quant_state_1);
      mh_2 = get_height(MINE,LIST->airline_2,LIST->quant_state_2);
      fprintf(fr,"(%d,%d)\n",mh_1,mh_2);
      LIST = LIST->next;
    }
  }
  //-------------------------------------------------------
  //усечение оператора R: add_states + сколько КС оставить
  void trunc_mine_field(int add_states){
    linked_states *lst = this->lstates;
    this->old_mf = this->mine_field;
    int max_col = 0;
    int curr_max_col = 0;
    for(int i=0; i<this->airlines_count; i++){
      curr_max_col = 0;
      for(int j=0; j<this->max_state_count; j++){
        for(int k=0; k<this->max_state_count; k++){
          if((this->mine_field[i][j][k]->get_id() == 5) && (k >= curr_max_col))
            curr_max_col = k+1;
        }
      }
      if(curr_max_col > max_col) max_col = curr_max_col;
    }
    max_col += add_states;
    minefield ****curr_mine;
    curr_mine = new minefield***[this->airlines_count];
    for(int i=0; i<this->airlines_count; ++i){
      curr_mine[i] = new minefield**[max_col];
      for(int j=0; j<max_col; ++j) {
        curr_mine[i][j] = new minefield*[max_col];
        for(int k=0; k<max_col; ++k){
          curr_mine[i][j][k] = new minefield;
        }
      }
    }
    int j_indx = 0;
    for(int i=0; i<this->airlines_count; i++){
      for(int j=0; j<max_col; j++){
        for(int k=0; k<max_col; k++){
          j_indx = this->max_state_count - max_col +j;
          curr_mine[i][j][k]->set_id(this->mine_field[i][j_indx][k]->get_id());
        }
      }
    }
    while(lst != NULL){
    // Выставляем по высотам
      for (int i = 0; i < max_col; ++i){
        if(curr_mine[lst->airline_1][i][lst->quant_state_1]->get_id() != 1  && curr_mine[lst->airline_2][i][lst->quant_state_2]->get_id() != 1){
          curr_mine[lst->airline_1][i][lst->quant_state_1]->add(lst->id,lst->airline_2,lst->quant_state_2);
          curr_mine[lst->airline_1][i][lst->quant_state_1]->set_id(5);
          curr_mine[lst->airline_2][i][lst->quant_state_2]->add(lst->id,lst->airline_1,lst->quant_state_1);
          curr_mine[lst->airline_2][i][lst->quant_state_2]->set_id(5);  
        }
      }
      lst = lst->next;
    }
    this->mine_field = curr_mine;
    this->old_state_count = this->max_state_count;
    this->max_state_count = max_col;
  }
  //=======================================================

  //=======================================================
  // Имитация полета по данному минному полю
  //=======================================================
  double imitation(FILE *res,int period, double alpha){
    // alpha вероятность выбросить SID, 1-alpha вероятность выбросить STAR
    if(alpha > 1 || alpha < 0) alpha = 0.5;
    minefield ****MINE;
    MINE = this->mine_field;
    numbers *tmp;
    int come_plane = 0; // Количество прилетевыших ВС (STAR)
    int away_plane = 0; // Количесто улетевших ВС (SID)
    int st_count = this->max_state_count;
    // имитaция периода     
    for (int p = 0; p < period+st_count; ++p){
      // printf("\n\n#%d\n",p);
      int sid_new = this->get_new_airline("SID");
      int star_new = this->get_new_airline("STAR");
      // int plane_new = rand() % this->airlines_count;
      int sid_num = 0;
      int star_num = 0;

      // printf("newSid = %d, NewStar = %d\n",sid_new, star_new);
      // по всем ВТ пробегаем
      // i - ВТ
      // j - высота
      // k - КС
      for (int i = 0; i < this->airlines_count; ++i){
      // Логика для SID
        if(strcmp(this->airlines[i]->get_sidstar(),"SID") == 0){
          // printf("SID - %s\n",this->airlines[i]->get_name() );
          for (int k = st_count-1; k >= 0; --k){
            
            for (int j = 0; j < st_count; ++j){
              // нашли состоние в котором находится ВС (по высоте)
             // printf("MINE[%d][%d][%d]\n",i,j,k );
              if(MINE[i][j][k]->is_plane()){
                int new_j = -1;
                // printf("ВС находится в состоянии j=%d, k=%d ",j,k);

                // последнее КС (уход из зоны наблюдения)
                if(k == st_count-1){
                  away_plane++;
                  MINE[i][j][k]->set_plane(false);
                  // printf("away -> MINE[%d][%d][%d]\n",i,j,k );
                  break;
                }
                // все остальные состояния
                // проверяем куда можно двигаться
                // j - текущая высота, j+1 - Эшелон выше, j-1 - Эшелон ниже (нужно проверить на существование j-1)
                // а так же можно ли их занять
                // k+1 - следующее состояние оно точно существует, т.к. последнее обрабатывается отдельно
                
                new_j = this->get_new_j(i,j,k,true);

               // определившись с тем, куда направляться, проверяем состояние - связное(5) или нет(0,1)
                // printf("-> новое положение  j=%d, k=%d\n",new_j,k+1);
                if(MINE[i][new_j][k+1]->get_id() != 5){
                  MINE[i][new_j][k+1]->set_plane(true);
                  MINE[i][j][k]->set_plane(false);
                  break;
                }
                // значит связное состоние, проверяем свободны ли другие состояния
                tmp = MINE[i][new_j][k+1]->get_links();
                while(tmp != NULL){
                  // printf("Возможен конфликт MINE[%d][%d][%d]  id=%d\n",i,new_j,k+1,tmp->id);
                  if(MINE[tmp->airline_id][new_j][tmp->qst]->is_plane()){
                    // printf("!!! Конфликт !!! MINE[%d][%d][%d] id = %d\n",tmp->airline_id,new_j,tmp->qst,tmp->id );
                    // выбираем кого оставить (кто выйграл)
                    // alpha - выроятность выбора SID
                    int remove_plane = rand() % 100; 
                    if((double)remove_plane >= (alpha*100)){
                      MINE[i][new_j][k+1]->set_plane(true);
                      MINE[tmp->airline_id][new_j][tmp->qst]->set_plane(false);
                      MINE[i][j][k]->set_plane(false); 
                      // printf("for SID rp = %g >= %g remove STAR MINE[%d][%d][%d]\n",(double)remove_plane,(100*alpha), tmp->airline_id,new_j,tmp->qst);
                    }else{
                      MINE[i][j][k]->set_plane(false); 
                      // printf("remove SID MINE[%d][%d][%d]\n",i,new_j,k-1);
                    }
                    break;
                  }
                  tmp = tmp->next;
                }
                // printf("Нет конфликта\n");
                MINE[i][new_j][k+1]->set_plane(true);
                MINE[i][j][k]->set_plane(false);
                break;
              }
            }
            // нулевое состояние и нужная ВТ- взлет
            if(k==0 && sid_num==sid_new && p < period){
              // printf(">>>нулевое состояние %d = %d\n",sid_num,sid_new );
              MINE[i][st_count-1][k]->set_plane(true);
              // printf("MINE[%d][%d][%d]->set_plane(%d)\n",i,st_count-1,k,MINE[i][st_count-1][k]->is_plane());
              continue;
            }
          }
          sid_num++;
      // Логика для STAR ----------------------------------
        }else{
          // printf("STAR - %s\n",this->airlines[i]->get_name() ); 
          // перебор КС
          for (int k = 0; k < st_count; ++k){
            // перебор ввысот
            for (int j = 0; j < st_count; ++j){
              if(MINE[i][j][k]->is_plane()){
                int new_j = -1;
                // printf("ВС находится в состоянии j=%d, k=%d ",j,k);
                // Последнее КС (по направлениюю движения)
                if(k == 0){
                  MINE[i][j][k]->set_plane(false);
                  come_plane++;
                  // printf("come -> MINE[%d][%d][%d]\n",i,j,k );
                  break;
                }
                // проверяем куда можно двигаться
                new_j = this->get_new_j(i,j,k,true);

                // выбрав куда лететь, проверяем свободно ли состояние
                // printf("-> новое положение  j=%d, k=%d\n",new_j,k-1);
                if(MINE[i][new_j][k-1]->get_id() != 5){
                  MINE[i][new_j][k-1]->set_plane(true);
                  MINE[i][j][k]->set_plane(false);
                  break;
                }
                // значит связное состоние, проверяем свободны ли другие состояния
                tmp = MINE[i][new_j][k-1]->get_links();
                while(tmp != NULL){
                  // printf("Возможен конфликт MINE[%d][%d][%d]  id=%d\n",i,new_j,k-1,tmp->id);
                  if(MINE[tmp->airline_id][new_j][tmp->qst]->is_plane()){
                    // printf("!!! Конфликт !!! MINE[%d][%d][%d] id = %d\n",tmp->airline_id,new_j,tmp->qst,tmp->id );
                    // выбираем кого оставить (кто выйграл )
                    // alpha - вероятность выбросить SID
                    int remove_plane = rand() % 100; 
                    if((double)remove_plane < (alpha*100)){
                      MINE[i][new_j][k-1]->set_plane(true);
                      MINE[tmp->airline_id][new_j][tmp->qst]->set_plane(false);
                      MINE[i][j][k]->set_plane(false); 
                      // printf("remove SID MINE[%d][%d][%d]\n",tmp->airline_id,new_j,tmp->qst);
                    }else{
                      MINE[i][j][k]->set_plane(false); 
                      // printf("for STAR rp = %g >= %g remove STAR MINE[%d][%d][%d]\n",(double)remove_plane,(alpha*100), i,new_j,k-1);
                    }
                    break;

                  }
                  tmp = tmp->next;
                }
                // printf("Нет конфликта\n");
                MINE[i][new_j][k-1]->set_plane(true);
                MINE[i][j][k]->set_plane(false);
                break;
              }
            }
            // новое ВС появляется
            if(star_num == star_new && k == st_count-1 && p < period){
            // if(i == plane_new && k == st_count-1){
              // если распределение не задано - то рандомно, елси задано по распределению
              if(this->distr == NULL){
                int new_star_j = rand() % st_count;
                MINE[i][new_star_j][k]->set_plane(true);
              }else{
                double *one_distr,sum;
                sum = 0;
                one_distr = new double[st_count];
                one_distr[0] = this->distr[star_new][0];
                for(int m = 0; m < st_count; ++m){
                  sum = sum + this->distr[star_new][m];
                  one_distr[m] = sum;
                }
                int new_star_j = rand() % 101; // т.е. числа от 0 до 100 включительно
                for (int m = 0; m < st_count; ++m){
                  if((m == 0 && new_star_j <= (int)(one_distr[m]*100)) || (new_star_j > (int)(one_distr[m-1]*100) && new_star_j <= (int)(one_distr[m]*100))){
                      new_star_j = m;
                      break;
                  }
                }
                delete[] one_distr;
                MINE[i][new_star_j][k]->set_plane(true);
                // printf("new_star = %d\n",new_star_j );
                // printf("MINE[%d][%d][%d]->set_plane(%d)\n",i,new_star_j,k,MINE[i][new_star_j][k]->is_plane());
              }
              continue;
            }
          }
          star_num++;
        }
      }
    }
    double all_plane = 100*(double)(come_plane + away_plane)/(double)(period*2);
    if(res != NULL){
      printf("alpha = %g всего:%d, come:%d; away:%d; All:%d -> %g\n",alpha, period*2, come_plane, away_plane,(come_plane+away_plane), all_plane );
      fprintf(res,"alpha = %g всего:%d, come:%d; away:%d; All:%d -> %g\n",alpha, period*2, come_plane, away_plane,(come_plane+away_plane), all_plane );
    } 
    //   printf("%s : %s \n",this->airlines[i]->get_name(),this->airlines[i]->get_sidstar() );  
    //   for (int j = 0; j < this->max_state_count; ++j){
    //     for (int k = 0; k < this->max_state_count; ++k){
    //       if(MINE[i][j][k]->get_id() == 5){
    //         printf("j=%d\tk=%d\tid=%d (j-Высоты, k-Номер КС)\n",j,k, MINE[i][j][k]->get_id() );
    //         tmp = MINE[i][j][k]->get_links();
    //         while(tmp != NULL){
    //           printf("\t id=%d  ,qst=%d  airline_id=%d\n",tmp->id,tmp->qst,tmp->airline_id);
    //           tmp = tmp->next;
    //         }
    //       }
    //     }  
    //   }
    // }
    return all_plane;
  }
  // получение дисперсии для результате имитационного эксперимента
  // n - количетсво элеметов в выборке
  // period - период, в течении которого будет браться 1 элемент выборки
  double get_dispersion(int n = 100, int period = 24*60,double alpha = 0.5){
    double Dx = 0; // Дисперсия
    double X[n]; // набор всех элементов
    double _X = 0; // Среднее
    for (int i = 0; i < n; ++i){
      X[i] = this->imitation(NULL,period,alpha);
      _X += X[i];
      // printf("#%d -> %g\n",i,X[i]);
    }
    _X = _X/n;
    // printf("_X = %g\n",_X );
    for (int i = 0; i < n; ++i){
      Dx += ((X[i]-_X)*(X[i]-_X))/n;
    }
    double SKO = sqrt(Dx);
    printf("Dx = %g   SKO = %g\n",Dx,SKO );
    return Dx;
  }
};
//=========================================================
#endif
